# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: jaewon

import logging

from coin.base.timestamp import get_timestamp
from coin.exchange.base.order_gateway import OrderSide, OrderType


class BitmexSimpleAggressor(object):
  def __init__(self, execution_params, order_gateway, logger=None):
    self._logger = logger or logging.getLogger('BitmexSimpleAggressor')
    self._og = order_gateway

    self._product = execution_params['product']
    self._native_symbol = execution_params['product'].native_symbol

    self._default_lot_size = execution_params.get('default_lot_size', 0)
    self._min_pos = execution_params['min_pos']
    self._max_pos = execution_params['max_pos']
    self._exclude_on_the_fly = execution_params.get('exclude_on_the_fly', True)
    self._order_update_period = (execution_params.get('order_update_period', 2) * (10**9))

    self._last_fire_ts = 0

  def cancel_all(self, amend_list=None, fire=True):
    amend_list = amend_list or []
    for order in self._og.get_working_order():
      if (order.product != self._native_symbol or not order.order_id.startswith('agg-')):
        continue
      if order.accepted:
        amend_list.append(self._og.make_bitmex_amend(order.order_id, leaves_qty=0))
    if fire and amend_list:
      self._og.amend_bulk(amend_list)

  def buy(self, price, qty=None, create_list=None, fire=True):
    now_ts = get_timestamp()
    if now_ts - self._last_fire_ts < self._order_update_period:
      return

    pos = self._og.get_position(self._product)
    if pos >= self._max_pos:
      return

    qty = min(self._max_pos - pos, qty or self._default_lot_size)
    if self._exclude_on_the_fly:
      on_the_fly_qty = 0
      for order in self._og.get_working_order():
        if (order.product != self._native_symbol or not order.order_id.startswith('agg-')):
          continue
        if order.order_side == OrderSide.BUY:
          if not order.accepted:
            on_the_fly_qty += order.qty
      qty -= on_the_fly_qty

    if qty <= 0:
      return

    create_list = [] if create_list is None else create_list
    order_id = 'agg-%d' % now_ts
    create_list.append(
        self._og.make_bitmex_order(self._native_symbol,
                                   price,
                                   qty,
                                   OrderSide.BUY,
                                   OrderType.LIMIT,
                                   order_id=order_id,
                                   post_only=False))
    if fire:
      self._og.submit_bulk(create_list)
      self._last_fire_ts = now_ts
    self._logger.info('BUY  %s %f @ %.1f, tag=agg', self._native_symbol, qty, price)

  def sell(self, price, qty=None, create_list=None, fire=True):
    now_ts = get_timestamp()
    if now_ts - self._last_fire_ts < self._order_update_period:
      return

    pos = self._og.get_position(self._product)
    if pos <= self._min_pos:
      return

    qty = min(pos - self._min_pos, qty or self._default_lot_size)
    if self._exclude_on_the_fly:
      on_the_fly_qty = 0
      for order in self._og.get_working_order():
        if (order.product != self._native_symbol or not order.order_id.startswith('agg-')):
          continue
        if order.order_side == OrderSide.SELL:
          if not order.accepted:
            on_the_fly_qty += order.qty
      qty -= on_the_fly_qty

    if qty <= 0:
      return

    create_list = [] if create_list is None else create_list
    order_id = 'agg-%d' % now_ts
    create_list.append(
        self._og.make_bitmex_order(self._native_symbol,
                                   price,
                                   qty,
                                   OrderSide.SELL,
                                   OrderType.LIMIT,
                                   order_id=order_id,
                                   post_only=False))
    if fire:
      self._og.submit_bulk(create_list)
      self._last_fire_ts = now_ts
    self._logger.info('SELL %s %f @ %.1f, tag=agg', self._native_symbol, qty, price)
